﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MetalSoda
{
    /// <summary>
    /// SSB queue
    /// </summary>
    [DebuggerDisplay("Queue: {Name}, Services: {ServicesCount}")]
    public class Queue : IDdlObject
    {        
        /// <summary>
        /// Queue name
        /// </summary>
        public readonly string Name;

        #region Private Fields
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        readonly OneToManyAssociation<Queue, Service> m_services; 
        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="MetalSoda.Contract"/> class.
        /// </summary>
        /// <param name="name">Queue name</param>
        public Queue(string name)
        {
            Name = name;
            m_services = new OneToManyAssociation<Queue, Service>(this,
                added: args => args.Ref.Queue = this,
                removed: args => args.Ref.Queue = null);
        }

        #region Properties
        /// <summary>
        /// Information about which stored procedure needs to start to process messages in this queue.
        /// </summary>
        public Activation Activation { get; set; }

        /// <summary>
        /// Gets total number of services targeting this queue.
        /// </summary>
        public int ServicesCount { get { return m_services.Count; } }

        /// <summary>
        /// Gets total number of contracts implemented by services targeting this queue.
        /// </summary>
        public int ContracsCount { get { return Contracts.Count(); } }

        /// <summary>
        /// Gets total number of message types that can be recieved by this queue.
        /// </summary>
        public int MessageTypesCount { get { return Contracts.Count(); } }

        /// <summary>
        /// Gets services targeting this queue.
        /// </summary>
        public IEnumerable<Service> Services { get { return m_services.AsEnumerable(); } }

        /// <summary>
        /// Gets contracts implemented by services targeting this queue.
        /// </summary>
        public IEnumerable<Contract> Contracts { get { return m_services.SelectMany(s => s.Contracts).Distinct(); } }

        /// <summary>
        /// Gets message types that can be recieved by this queue.
        /// </summary>
        public IEnumerable<MessageType> MessageTypes { get { return Contracts.SelectMany(c => c.MessageTypes).Distinct(); } } 
        #endregion

        #region Methods
        /// <summary>
        /// Registers the given service to to target this queue
        /// </summary>
        /// <param name="service">Service</param>
        /// <returns>Self</returns>
        public Queue AddService(Service service)
        {
            if (Service(service.Name) != null)
            {
                if (Service(service.Name) == service) { return this; }
                throw new InvalidOperationException();
            }
            m_services.Add(service);
            return this;
        }

        /// <summary>
        /// Removes the specified service from services targeting this queue.
        /// </summary>
        /// <param name="service">Service instance</param>
        /// <returns>Self</returns>
        public Queue RemoveService(Service service)
        {
            if (Object.ReferenceEquals(service, null)) { return this; }
            m_services.Remove(Service(service.Name));
            return this;
        }

        /// <summary>
        /// Removes the specified service from services targeting this queue.
        /// </summary>
        /// <param name="serviceName">Service name</param>
        /// <returns>Self</returns>
        public Queue RemoveService(string serviceName)
        {
            m_services.Remove(Service(serviceName));
            return this;
        }

        /// <summary>
        /// Finds the service targeting this queue by the services name
        /// </summary>
        /// <param name="name">Service name</param>
        /// <returns>Service instance</returns>
        public Service Service(string name)
        {
            return m_services.Where(s => Utils.AreSame(s.Name, name)).SingleOrDefault();
        } 
        #endregion

        #region IDdlObject Implementation

        /// <summary>
        /// Generates a sequence on the CREATE batches.
        /// </summary>
        /// <returns>T-SQL batches</returns>
        public IEnumerable<string> GenerateCreateBatches()
        {
            yield return new SQLScript.CreateQueueRuntimeTextTemplate(this).TransformText();
        }

        /// <summary>
        /// Generates a sequence on the ALTER batches.
        /// </summary>
        /// <returns>T-SQL batches</returns>
        public IEnumerable<string> GenerateAlterBatches()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Generates a sequence on the DELETE batches.
        /// </summary>
        /// <returns>T-SQL batches</returns>
        public IEnumerable<string> GenerateDeleteBatches()
        {
            throw new NotImplementedException();
        } 
        #endregion
    }
}
